package ru.ifmo.ctd.year2008.notepad.client;

import ru.ifmo.ctd.year2008.notepad.IdGenerator;
import ru.ifmo.ctd.year2008.notepad.IdGeneratorStupidImpl;
import ru.ifmo.ctd.year2008.notepad.Line;
import ru.ifmo.ctd.year2008.notepad.Text;
import ru.ifmo.ctd.year2008.notepad.diff.DiffCalculator;
import ru.ifmo.ctd.year2008.notepad.diff.DiffSet;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;

import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MaximizeAction;

public class Client implements ClientInterface {
	private GUI gui;
	String host;
	int port;

	Socket connectionWithServer;
	ObjectOutputStream output;
	ObjectInputStream input;
	IdGenerator idGenerator = new IdGeneratorStupidImpl();
	Text text;

	public void setGUI(GUI gui) {
		this.gui = gui;
	}

	@Override
	public List<String> getDocumentsList() {
		try {
			output.writeObject("List");
			String[] ok = (String[]) input.readObject();
			return Arrays.asList(ok);
		} catch (Exception e) {
			e.printStackTrace();
			return Arrays.asList("Error", "No documents for you");
		}
	}

	@Override
	public Socket connect(String host, int port) {
		try {
			this.host = host;
			this.port = port;
			Socket socket = new Socket(host, port);
			this.connectionWithServer = socket;
			this.output = new ObjectOutputStream(
					connectionWithServer.getOutputStream());
			this.input = new ObjectInputStream(
					connectionWithServer.getInputStream());
			return socket;
		} catch (IOException e) {
			return null;
		}
	}

	public void disconnect() {
		try {
			this.connectionWithServer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public Text openToEdit(String doc) {
		try {
			output.writeObject("Open " + doc);
			Text ok = (Text) input.readObject();
			text = ok;

			// //TODO
			// if (text == null) text = new Text(Arrays.asList(new Line(0,
			// "")));

			updateTextFieldInGUI();
			return ok;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public void close() {
		try {
			output.writeObject("Close");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void sendDiff(List<String> modifiedText)
			throws IOException {
		// TODO
		// if (text == null) text = new Text(Arrays.asList(new Line(0, "")));

		DiffSet diffSet = DiffCalculator.getDiffSet(text, modifiedText,
				idGenerator);
		if (diffSet.size() == 0) {
			return;
		}
		System.out.println(diffSet);
		output.writeObject("Commit");
		output.writeObject(diffSet);
	}

	public void receiveText() {
		Text t;

		try {
			t = (Text) input.readObject();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		synchronized (this) {
			this.text = t;
		}
		updateTextFieldInGUI();
	}

	private void updateTextFieldInGUI() {
		int position = gui.textArea.getCaretPosition();
		gui.setText(getText(text));
		try {
			position = Math.max(position, 0);
			position = Math.min(position, gui.textArea.getText().length());
			gui.textArea.setCaretPosition(position);
		} catch (Exception e) {
		}
	}

	private static String getText(Text text) {
		List<Line> lines = text.getLines();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < lines.size(); i++) {
			if (i > 0) {
				sb.append('\n');
			}
			sb.append(lines.get(i).getString());
		}
		return sb.toString();
	}

}
